#pragma once

#include "Common.h"
#include "Base.h"

// 消息抽象实现
namespace rpc
{
    using Address = std::pair<string, int>;

    class JsonMessage : public BaseMessage
    {
    public:
        using ptr = std::shared_ptr<JsonMessage>;

        virtual string serialize() override
        {
            string body;
            if (!JsonUtil::serialize(_body, body))
            {
                return string();
            }

            return body;
        }

        virtual bool unserialize(const string &body) override
        {
            return JsonUtil::unserialize(body, _body);
        }

    protected:
        Json::Value _body;
    };

    class JsonRequest : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonRequest>;
    };

    class JsonResponse : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonResponse>;

        virtual bool check() override
        {
            // 在响应中，大部分的时间只有响应状态码
            // 因此只需要判断是否存在响应状态码，以及类型是否正确即可
            if (_body[KEY_RCODE].isNull())
            {
                ELOG("响应状态码未找到!");
                return false;
            }

            if (!_body[KEY_RCODE].isIntegral())
            {
                ELOG("响应状态码类型错误!");
                return false;
            }

            return true;
        }

        virtual RCode rcode()
        {
            return (RCode)_body[KEY_RCODE].asInt();
        }

        virtual void setRcode(RCode code)
        {
            _body[KEY_RCODE] = (int)code;
        }
    };

    class RpcRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<RpcRequest>;

        virtual bool check() override
        {
            if (_body[KEY_METHOD].isNull() ||
                !_body[KEY_METHOD].isString())
            {
                ELOG("Rpc请求中没有方法名称或方法名称类型错误！")
                return false;
            }

            if (_body[KEY_PARAMS].isNull() ||
                !_body[KEY_PARAMS].isObject())
            {
                ELOG("调用方法没有参数或参数类型错误！")
                return false;
            }

            return true;
        }

        virtual string method() const
        {
            return _body[KEY_METHOD].asString();
        }

        virtual void setMethod(const string &method)
        {
            _body[KEY_METHOD] = method;
        }

        virtual Json::Value params() const
        {
            return _body[KEY_PARAMS];
        }

        virtual void setParams(const Json::Value &value)
        {
            _body[KEY_PARAMS] = value;
        }
    };

    class TopicRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<TopicRequest>;

        virtual bool check() override
        {
            if (_body[KEY_TOPIC_KEY].isNull() ||
                !_body[KEY_TOPIC_KEY].isString())
            {
                ELOG("主题请求没有主题名或主题名类型错误！")
                return false;
            }

            if (_body[KEY_OPTYPE].isNull() ||
                !_body[KEY_OPTYPE].isIntegral())
            {
                ELOG("主题请求中没有操作类型或操作类型错误！")
                return false;
            }

            if (_body[KEY_OPTYPE].asInt() == (int)TopicOpType::TOPIC_PUBLISH &&
                (_body[KEY_TOPIC_MSG].isNull() ||
                 !_body[KEY_TOPIC_MSG].isString()))
            {
                ELOG("主题请求为发布消息但是没有消息或消息类型错误！")
                return false;
            }

            return true;
        }

        virtual string topic() const
        {
            return _body[KEY_TOPIC_KEY].asString();
        }

        virtual void setTopic(const string &topic)
        {
            _body[KEY_TOPIC_KEY] = topic;
        }

        virtual TopicOpType opType() const
        {
            return (TopicOpType)_body[KEY_OPTYPE].asInt();
        }

        virtual void setOpType(TopicOpType op)
        {
            _body[KEY_OPTYPE] = (int)op;
        }

        virtual string msg() const
        {
            return _body[KEY_TOPIC_MSG].asString();
        }

        virtual void setMsg(const string &msg)
        {
            _body[KEY_TOPIC_MSG] = msg;
        }
    };

    class ServiceRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<ServiceRequest>;

        virtual bool check() override
        {
            if (_body[KEY_METHOD].isNull() ||
                !_body[KEY_METHOD].isString())
            {
                ELOG("服务请求中没有方法名称或方法名称类型错误！")
                return false;
            }

            if (_body[KEY_OPTYPE].isNull() ||
                !_body[KEY_OPTYPE].isIntegral())
            {
                ELOG("服务请求中没有操作类型或操作类型错误！")
                return false;
            }

            if (_body[KEY_OPTYPE].asInt() != (int)ServiceOpType::SERVICE_DISCOVER &&
                (_body[KEY_HOST].isNull() || !_body[KEY_HOST].isObject() ||
                 _body[KEY_HOST][KEY_HOST_IP].isNull() || !_body[KEY_HOST][KEY_HOST_IP].isString() ||
                 _body[KEY_HOST][KEY_HOST_PORT].isNull() || !_body[KEY_HOST][KEY_HOST_PORT].isIntegral()))
            {
                ELOG("服务请求没有主机信息！")
                return false;
            }

            return true;
        }

        virtual string method() const
        {
            return _body[KEY_METHOD].asString();
        }

        virtual void setMethod(const string &method)
        {
            _body[KEY_METHOD] = method;
        }

        virtual ServiceOpType opType() const
        {
            return (ServiceOpType)_body[KEY_OPTYPE].asInt();
        }

        virtual void setOpType(ServiceOpType type)
        {
            _body[KEY_OPTYPE] = (int)type;
        }

        virtual Address host()
        {
            return std::make_pair<string, int>(_body[KEY_HOST][KEY_HOST_IP].asString(), _body[KEY_HOST][KEY_HOST_PORT].asInt());
        }

        virtual void setHost(const Address &address)
        {
            Json::Value addr;
            addr[KEY_HOST_IP] = address.first;
            addr[KEY_HOST_PORT] = address.second;

            _body[KEY_HOST] = addr;
        }
    };

    class RpcResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<RpcResponse>;

        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() ||
                !_body[KEY_RCODE].isIntegral())
            {
                ELOG("Rpc调用响应码为空或响应码类型错误！")
                return false;
            }

            if (_body[KEY_RESULT].isNull())
            {
                ELOG("Rpc调用响应结果为空")
                return false;
            }

            return true;
        }

        virtual Json::Value result() const
        {
            return _body[KEY_RESULT];
        }

        virtual void setResult(const Json::Value &rest)
        {
            _body[KEY_RESULT] = rest;
        }
    };

    class TopicResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<TopicResponse>;
    };

    class ServiceResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<ServiceResponse>;

        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() ||
                !_body[KEY_RCODE].isIntegral())
            {
                ELOG("服务响应码为空或响应码类型错误！")
                return false;
            }

            if (_body[KEY_OPTYPE].isNull() || !_body[KEY_OPTYPE].isIntegral() ||
                (_body[KEY_OPTYPE].asInt() == (int)ServiceOpType::SERVICE_DISCOVER &&
                 (_body[KEY_METHOD].isNull() || !_body[KEY_METHOD].isString() ||
                  _body[KEY_HOST].isNull() || !_body[KEY_HOST].isArray())))
            {

                ELOG("服务响应中响应信息错误！")
                return false;
            }

            return true;
        }

        ServiceOpType opType() const
        {
            return (ServiceOpType)_body[KEY_OPTYPE].asInt();
        }

        void setOpType(ServiceOpType type)
        {
            _body[KEY_OPTYPE] = (int)type;
        }

        string method() const
        {
            return _body[KEY_METHOD].asString();
        }

        void setMethod(const string &method)
        {
            _body[KEY_METHOD] = method;
        }

        void setHost(const vector<Address> &vec)
        {
            for (auto &addr : vec)
            {
                Json::Value val;

                val[KEY_HOST_IP] = addr.first;
                val[KEY_HOST_PORT] = addr.second;

                _body[KEY_HOST].append(val);
            }
        }

        vector<Address> host() const
        {
            vector<Address> addrs;

            int sz = _body[KEY_HOST].size();
            for (int i{}; i < sz; i++)
            {
                addrs.emplace_back(
                    _body[KEY_HOST][i][KEY_HOST_IP].asString(), _body[KEY_HOST][i][KEY_HOST_PORT].asInt());
            }

            return addrs;
        }
    };

    class MessageFactory
    {
    public:
        static BaseMessage::ptr create(MType type)
        {
            switch (type)
            {
            case MType::REQ_RPC:
                return std::make_shared<RpcRequest>();
            case MType::RSP_RPC:
                return std::make_shared<RpcResponse>();
            case MType::REQ_TOPIC:
                return std::make_shared<TopicRequest>();
            case MType::RSP_TOPIC:
                return std::make_shared<TopicResponse>();
            case MType::REQ_SERVICE:
                return std::make_shared<ServiceRequest>();
            case MType::RSP_SERVICE:
                return std::make_shared<ServiceResponse>();
            }

            // 否则构建空指针
            return BaseMessage::ptr();
        }

        template <typename T, typename... Args>
        static std::shared_ptr<T> create(Args... args)
        {
            return std::make_shared<T>(std::forward<Args>(args)...);
        }
    };

} // rpc